'use strict';
let PDFDocment = require('pdfkit');
let Enumerable = require('linq');
let BaseRender = require('./BaseRender');

/**
 *普通数据源自动渲染
 *
 * @class NormalDataAutoRender
 * @extends {BaseRender}
 */
class NormalDataAutoRender extends BaseRender {
    /**
     *渲染
     *
     * @memberof NormalDataAutoRender
     */
    _render() {
        this._groupMasterFields();
        this._renderTitle();
        this._renderHeader();
        this._renderTableHeader();
        this._renderTable();
    }

    /**
     *字段按头部和尾部分组
     *
     * @memberof NormalDataAutoRender
     */
    _groupMasterFields() {
        let fields = Enumerable.from(this._data.masterFields).where(field => !field.isTitle && !field.hidden).toArray();
        Enumerable.from(fields)
            .groupBy(field => field.isFooter)
            .forEach(group => {
                group.key() ? (this._footerFields = group.getSource()) : (this._headerFields = group.getSource());
            });
    }

    /**
     *渲染标题
     *
     * @memberof NormalDataAutoRender
     */
    _renderTitle() {
        let titleField = Enumerable.from(this._data.masterFields).firstOrDefault(field => field.isTitle);
        let title = titleField ? titleField.value : this._data.reportName;
        this._renderText(title, {
            left: 0,
            top: 50,
            name: 'blod',
            size: this._pageSetting.fontSize * 2,
            align: 'center',
            width: this._pageSetting.width,
        });
    }

    /**
     *渲染头部
     *
     * @memberof NormalDataAutoRender
     */
    _renderHeader() {
        this._renderHeaderAndFooter(this._headerFields);
    }

    /**
     *渲染尾部
     *
     * @param {*} top
     * @memberof NormalDataAutoRender
     */
    _renderFooter(top) {
        this._renderHeaderAndFooter(this._footerFields, top);
    }

    /**
     *渲染头部和尾部
     *
     * @param {*} fields
     * @param {*} top
     * @memberof NormalDataAutoRender
     */
    _renderHeaderAndFooter(fields, top) {
        if (!fields) return;
        let pageSetting = this._pageSetting;
        if (!top) top = 90;
        let width = 0;
        Enumerable.from(fields).forEach(field => {
            if (field.name.indexOf(':') === -1 && field.name.indexOf('：') === -1) {
                field.name += ':';
            }
            width += this._getTextWidth(`${field.name}${field.value}`);
        });
        let left = pageSetting.tableMargin;
        let whiteWidth = (pageSetting.width - pageSetting.tableMargin * 2 - width) / (fields.length - 1);
        Enumerable.from(fields).forEach(field => {
            let text = `${field.name}${field.value}`;
            let textWidth = this._getTextWidth(text);
            this._renderText(text, {
                left,
                top,
                width: textWidth + 10,
            });
            left += textWidth + whiteWidth;
        });
    }

    /**
     *渲染表头：4次遍历,性能问题,后面考虑存储第一次计算的结果
     *
     * @memberof NormalDataAutoRender
     */
    _renderTableHeader() {
        let data = this._data;
        let pageSetting = this._pageSetting;
        let tableWidth = Enumerable.from(data.detailFields).sum(field => field.columnWidth || 50);
        let top = pageSetting.tableTop;
        let tableRealWidth = pageSetting.width - pageSetting.tableMargin * 2;
        // 字段分组：[a,[b,c],[d,e],f] 
        let groupFields = [];
        let tempFields = {};
        for (let i = 0; i < data.detailFields.length; i++) {
            let field = data.detailFields[i];
            if (!field.groupName) {
                groupFields.push(field);
                continue;
            }
            if (!tempFields.groupName) {
                tempFields = {
                    groupName: field.groupName,
                    fields: []
                };
            }
            if (tempFields.groupName === field.groupName) {
                tempFields.fields.push(field);
            } else {
                groupFields.push(tempFields.fields);
                tempFields = {
                    groupName: field.groupName,
                    fields: [field]
                };
            }
            if (i == data.detailFields.length - 1) {
                groupFields.push(tempFields.fields);
            }
        }
        let maxHeight = pageSetting.fontSize + 9;
        let maxHeight1 = 0; // 多表头列 子表头最大高度
        let maxHeight2 = 0; // 多表头列 父表头最大高度
        let tempLeft = pageSetting.tableMargin;
        Enumerable.from(groupFields).forEach(field => {
            if (Array.isArray(field)) {
                let tempWidth = 0;
                Enumerable.from(field).forEach(f => {
                    // 计算并记录真实单元格宽度
                    let realWidth = (f.realWidth = (tableRealWidth * (f.columnWidth || 50)) / tableWidth);
                    // 记录左边距
                    f.left = tempLeft;
                    tempWidth += realWidth;
                    tempLeft += realWidth;
                    let height = this._getTextHeight(f.caption, {
                        width: realWidth - 10,
                        align: f.headerAlign || 'center',
                        name: 'blod',
                    }) + 9;
                    if (height > maxHeight1) maxHeight1 = height;
                });
                let f = field[0];
                let height = this._getTextHeight(f.caption, {
                    width: tempWidth - 10,
                    align: f.headerAlign || 'center',
                    name: 'blod',
                }) + 9;
                f.groupWidth = tempWidth;
                if (height > maxHeight2) maxHeight2 = height;
                return;
            }
            // 计算并记录真实单元格宽度
            let realWidth = (field.realWidth = (tableRealWidth * (field.columnWidth || 50)) / tableWidth);
            // 记录左边距
            field.left = tempLeft;
            tempLeft += realWidth;
            let height = this._getTextHeight(field.caption, {
                width: realWidth - 10,
                align: field.headerAlign || 'center',
                name: 'blod',
            }) + 9;
            if (height > maxHeight) maxHeight = height;
        });
        if (maxHeight1 + maxHeight2 > maxHeight) maxHeight = maxHeight1 + maxHeight2;
        pageSetting.tableHeaderHeight = maxHeight;
        // 渲染
        Enumerable.from(groupFields).forEach(field => {
            if (Array.isArray(field)) {
                // 渲染父表头
                let groupFiled = field[0];
                this._renderTextAndRect(groupFiled.groupName, {
                    left: groupFiled.left,
                    top,
                    width: groupFiled.groupWidth,
                    height: maxHeight1,
                    align: 'center',
                    name: 'blod',
                });
                Enumerable.from(field).forEach(f => {
                    this._renderTextAndRect(f.caption, {
                        left: f.left,
                        top: top + maxHeight1,
                        width: f.realWidth,
                        height: maxHeight2,
                        align: 'center',
                        name: 'blod',
                    });
                });
                return;
            }
            this._renderTextAndRect(field.caption, {
                left: field.left,
                top,
                width: field.realWidth,
                height: maxHeight,
                align: field.headerAlign || 'center',
                name: 'blod',
                valign: 'center',
            });
        });
    }

    /**
     *渲染表格数据
     *
     * @memberof NormalDataAutoRender
     */
    _renderTable() {
        let top = this._data.dataGroupField ? this._renderGroupTable() : this._renderNormalTable();
        this._handleAddPage(top, false);
    }

    /**
     *渲染普通表格
     *
     * @memberof NormalDataAutoRender
     */
    _renderNormalTable() {
        let data = this._data;
        let pageSetting = this._pageSetting;
        let top = pageSetting.tableTop + pageSetting.tableHeaderHeight;
        let nextRowHeight = 0;
        for (let i = 0; i < data.detailData.itemList.length; i++) {
            let item = data.detailData.itemList[i];
            let maxRowHeight = nextRowHeight || this._getMaxRowHeight(item);
            // 渲染数据
            Enumerable.from(data.detailFields).forEach(field => {
                let text = item[field.dataField];
                this._renderTextAndRect(text, {
                    left: field.left,
                    top,
                    width: field.realWidth,
                    height: maxRowHeight,
                    align: field.textAlign || 'left',
                });
            });
            top += maxRowHeight;
            if (i === data.detailData.itemList.length - 1) break;
            nextRowHeight = this._getMaxRowHeight(data.detailData.itemList[i + 1]);
            // 判断剩下的表格高度是否够渲染下一行
            if (pageSetting.tableMaxHeight - (top - pageSetting.tableTop) < nextRowHeight) {
                top = this._handleAddPage(top);
            }
        }
        return top;
    }

    /**
     *获取最大行高
     *
     * @param {*} item
     * @param {*} notMerge 不包含合并行
     * @returns
     * @memberof NormalDataAutoRender
     */
    _getMaxRowHeight(item, notMerge = false) {
        let maxRowHeight = this._pageSetting.fontSize + 10;
        Enumerable.from(this._data.detailFields).forEach(field => {
            if (notMerge && field.mergeSameRow) return;
            let text = item[field.dataField];
            let height = this._getTextHeight(text, {
                width: field.realWidth - 10,
            });
            if (height > maxRowHeight) {
                maxRowHeight = height + 9;
            }
        });
        return maxRowHeight;
    }

    /**
     *渲染分组表格
     *
     * @returns
     * @memberof NormalDataAutoRender
     */
    _renderGroupTable() {
        let data = this._data;
        let pageSetting = this._pageSetting;
        let top = pageSetting.tableTop + pageSetting.tableHeaderHeight;
        // 数据分组
        let groups = [];
        Enumerable.from(data.detailData.itemList)
            .groupBy(item => item[data.dataGroupField])
            .forEach(group => groups.push(group.getSource()));
        // 遍历分组
        for (let i = 0; i < groups.length; i++) {
            let items = groups[i];
            // 下一行最大行高
            let nextMaxRowHeight = 0;
            // 临时top
            let tempTop = top;
            // 跨页标识
            let extendFlag = false;
            // 遍历数据
            for (let j = 0; j < items.length; j++) {
                let item = items[j];
                // 判断该行是否已渲染 没有则继续
                if (item.render) continue;
                // 第1次遍历字段：获取非合并行行高
                let maxRowHeight = nextMaxRowHeight || this._getMaxRowHeight(item, true);
                // 第2次遍历字段：渲染非合并行
                Enumerable.from(data.detailFields).forEach(field => {
                    if (field.mergeSameRow) return;
                    this._renderTextAndRect(item[field.dataField], {
                        left: field.left,
                        top,
                        width: field.realWidth,
                        height: maxRowHeight,
                        align: field.textAlign || 'left',
                    });
                });
                // 标记改行已渲染
                item.render = true;
                // 记录高度
                top += maxRowHeight;
                // 判断是否为最后一项
                if (j === items.length - 1) break;
                // 计算下一行高度并记录
                nextMaxRowHeight = this._getMaxRowHeight(items[j + 1], true);
                // 判断剩下高度是否够渲染下一行
                if (pageSetting.tableMaxHeight - (top - pageSetting.tableTop) > nextMaxRowHeight) continue;
                // 渲染合并行
                this._renderMergeRow(item, top, tempTop);
                // 换页处理
                top = this._handleAddPage(top);
                extendFlag = true;
                break;
            }
            if (extendFlag) {
                i--;
                continue;
            }
            // 渲染合并行
            this._renderMergeRow(items[0], top, tempTop);
            // 判断是否为最后一组
            if (i === groups.length - 1) break;
            // 获取下一组第一行高度
            let nextGroupFirstRowHeight = this._getMaxRowHeight(groups[i + 1][0], true);
            // 判断剩余高度是否够渲染下一组第一个
            if (pageSetting.tableMaxHeight - (top - pageSetting.tableTop) > nextGroupFirstRowHeight) continue;
            // 换页处理
            top = this._handleAddPage(top);
        }
        return top;
    }

    /**
     *渲染合并行
     *
     * @param {*} item
     * @param {*} top
     * @param {*} tempTop
     * @memberof NormalDataAutoRender
     */
    _renderMergeRow(item, top, tempTop) {
        Enumerable.from(this._data.detailFields).forEach(field => {
            if (!field.mergeSameRow) return;
            this._renderTextAndRect(item[field.dataField], {
                left: field.left,
                top: tempTop,
                width: field.realWidth,
                height: top - tempTop,
                align: field.textAlign || 'left',
                valign: 'center',
            });
        });
    }

    /**
     *获取组合表格最大行高
     *
     * @param {*} items
     * @returns
     * @memberof NormalDataAutoRender
     */
    _getGroupMaxRowHeight(items) {
        let data = this._data;
        let pageSetting = this._pageSetting;
        let maxRowHeight = pageSetting.fontSize + 10;
        let cellHeightList = [];
        // 取得最高行高
        Enumerable.from(data.detailFields).forEach(field => {
            if (field.mergeSameRow) {
                let text = items[0][field.dataField];
                let height = this._getTextHeight(text, {
                    width: field.realWidth - 10,
                });
                if (height > maxRowHeight) {
                    maxRowHeight = height + 9;
                }
                return;
            }
            for (let i = 0; i < items.length; i++) {
                let item = items[i];
                let cellHeight =
                    this._getTextHeight(item[field.dataField], {
                        width: field.realWidth - 10,
                    }) + 9;
                if (cellHeightList.length < i + 1) {
                    cellHeightList.push(cellHeight);
                } else if (cellHeightList[i] < cellHeight) {
                    cellHeightList[i] = cellHeight;
                }
            }
        });
        if (cellHeightList.length !== 0) {
            let tempMaxHeight = Enumerable.from(cellHeightList).sum();
            // 合并行大于组合行的情况 按照比例计算组合行各行的高度
            if (maxRowHeight > tempMaxHeight) {
                for (let i = 0; i < cellHeightList.length; i++) {
                    cellHeightList[i] = (cellHeightList[i] / tempMaxHeight) * maxRowHeight;
                }
            } else {
                maxRowHeight = tempMaxHeight;
            }
        }
        return {
            maxRowHeight,
            cellHeightList,
        };
    }

    /**
     *处理分页
     *
     * @param {*} top
     * @param {*} flag
     * @returns
     * @memberof NormalDataAutoRender
     */
    _handleAddPage(top, flag = true) {
        let pageSetting = this._pageSetting;
        top += this._renderSumRow(top);
        top += 10;
        this._renderFooter(top);
        if (flag) {
            this._doc.addPage();
            this._renderTitle();
            this._renderHeader();
            this._renderTableHeader();
            top = pageSetting.tableTop + pageSetting.tableHeaderHeight;
        }
        return top;
    }

    /**
     *判断数据源是否分组
     *
     * @returns
     * @memberof NormalDataAutoRender
     */
    _isGroupDetailData() {
        let data = this._data;
        let dataGroupField = data.dataGroupField;
        if (!dataGroupField) return false;
        let field = Enumerable.from(data.detailFields).firstOrDefault(f => f.dataField === dataGroupField);
        if (!field) return false;
        return true;
    }

    /**
     *渲染统计行
     *
     * @param {*} top
     * @returns
     * @memberof NormalDataAutoRender
     */
    _renderSumRow(top) {
        let data = this._data;
        if (!data.datailSumTexts || data.datailSumTexts.length === 0) return 0;
        let pageSetting = this._pageSetting;
        let left = pageSetting.tableMargin;
        let maxRowHeight = pageSetting.fontSize + 10;
        Enumerable.from(data.detailFields).forEach(field => {
            let text = '';
            let sumText = Enumerable.from(data.datailSumTexts).firstOrDefault(s => s.name === field.name);
            if (sumText) {
                text = sumText.sumText;
            }
            field.text = text;
            let height =
                this._getTextHeight(text, {
                    width: field.realWidth - 10,
                    align: field.textAlign || 'left',
                }) + 9;
            if (height > maxRowHeight) maxRowHeight = height;
        });
        Enumerable.from(data.detailFields).forEach(field => {
            this._renderTextAndRect(field.text, {
                left,
                top,
                width: field.realWidth,
                height: maxRowHeight,
                align: field.textAlign || 'left',
            });
            left += field.realWidth;
        });
        return maxRowHeight;
    }
}

exports = module.exports = NormalDataAutoRender;